import { consts } from "@/module-00-codebase/pkg-00-const";
import { Bi } from "@/module-00-codebase/pkg-01-container";
import { PendingPromise, pendingResolve } from "@/module-00-codebase/pkg-02-tool";
import { RpcResult } from "@/module-00-codebase/pkg-08-entity/rpc-result";

export class RestRpcHandle {
  public isSigning = false;
  public async success(params: any, res: any) {
    // 0. success!
    if (res.result === true) {
      return res;
    }
    // 2. token expired
    else if (res.message === consts.errot_token_expired) {
      const pending = pendingResolve<RpcResult>();
      cacheExpireds({ params, pending });
      return pending;
    }
    // 3. error occurs
    else {
      throw new Error(res.message || "Unknow error occured on server.");
    }
  }
}
let isSigning = false;
const expiredOptions: { params: any; pending: PendingPromise<any> }[] = [];
const cacheExpireds = (rpcArgs: { params: any; pending: PendingPromise<RpcResult> }) => {
  // 1. cache
  expiredOptions.push(rpcArgs);
  if (!isSigning && (isSigning = true)) {
    return (async () => {
      try {
        // 2. login
        Bi.loading.on("Reconnecting...");
        const account = Bi.cacheManager.read("account");
        let res: RpcResult;
        if (!account?.password || !account?.username) {
          throw new Error("No account info cached.");
        } else if (!(res = await Bi.sign.in(account?.username, account?.password)).result) {
          await Bi.sign.out();
          throw new Error(res?.message || "User signed out, operation cancelled.");
        } else expiredOptions.forEach(pmcb => Bi.rpc.send(pmcb.params).then(pmcb.pending.resolve).catch(pmcb.pending.reject));
      } catch (ex: unknown) {
        const e = ex instanceof Error ? ex : new Error(JSON.stringify(ex));
        expiredOptions.forEach(pmcb => pmcb.pending.reject(e));
      } finally {
        expiredOptions.length = 0;
        Bi.loading.off();
        isSigning = false;
      }
    })();
  }
};
